/**
 * 给定4种拼块，记作11、00、01和10
 * 1表示凸起，0表示凹陷，凸起和凹陷才能拼接
 * 每种拼块的数量分别是C1、C2、C3和C4，问一共有多少种拼接方案
 * 
 * 注意到11和00必须交替放置，即2个11之间必须要放00，不然无法放置
 * 于是得到初步的判断, |C1 - C2| <= 1， 否则方案数为零
 * 
 * 再分类考虑，首先考虑C1 == C2 + 1的情况，即形如
 *       11 ... 00 ... 11 ... 00 ... 11
 * 再考虑01和10如何放置。先考虑01，会发现01只能放在11的右边
 * 一共有C1个这样的位置，当然同一个位置可以放任意01
 * 因此这是一个球同盒异可空的模型，其方案数是 C(qiu+he-1, he-1)
 * 对10有同样的考虑。
 * 对其他情况也有同理的讨论
 */
#include <bits/stdc++.h>
using namespace std;

#include <bits/extc++.h>
using namespace __gnu_pbds;

using llt = long long;
llt const MOD = 998244353LL;

llt qpow(llt a, llt n){
    llt r = 1;
    while(n){
        if(n & 1) r = r * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return r;
}

llt inv(llt a){return qpow(a, MOD-2LL);}

vector<llt> Fac, IFac;

void init(int n){
    Fac.assign(n + 1, 0);
    Fac[0] = 1;
    for(int i=1;i<=n;++i) Fac[i] = Fac[i - 1] * i % MOD;
    
    IFac.assign(n + 1, 0);
    IFac[n] = inv(Fac[n]);
    for(int i=n-1;i>=0;--i) IFac[i] = IFac[i + 1] * (i + 1) % MOD;
    assert(IFac[0] == 1 and IFac[1] == 1);
    return;
}

llt C(llt n, llt m){
    if(m < 0 or m > n) return 0;
    return Fac[n] * IFac[n - m] % MOD * IFac[m] % MOD;
}

llt C1, C2, C3, C4;

llt f(llt qiu, llt he) {
    return C(qiu + he - 1, he - 1);
}

llt proc(){
    if(abs(C1 - C2) > 1) return 0;

    if(C2 + 1 == C1) return f(C3, C1) * f(C4, C1) % MOD;

    if(C1 + 1 == C2) return f(C3, C2) * f(C4, C2) % MOD;

    if(C1 == 0){
        if(C3 == 0 or C4 == 0) return 1;
        return 0;
    }

    auto t = f(C3, C2 + 1) * f(C4, C1) % MOD;
    auto t2 = f(C4, C1 + 1) * f(C3, C2) % MOD;
    return (t + t2) % MOD;
}

void work(){
    cin >> C1 >> C2 >> C3 >> C4;
    cout << proc() << "\n";
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    init(2E6);
    int nofkase = 1;
    cin >> nofkase;
    while(nofkase--) work();
    return 0;
}